/*
 * FaceCat图形通讯框架
 * 著作权编号:2015SR229355+2020SR0266727
 * 上海卷卷猫信息技术有限公司
 */

#include "stdafx.h"
#include "FCGrid.h"

namespace FaceCat{
    GridRowCompare::GridRowCompare(){
        m_columnIndex = 0;
        m_type = 0;
    }
    
    GridRowCompare::~GridRowCompare(){
    }
    
    bool GridRowCompare::operator()(FCGridRow *x, FCGridRow *y){
        FCGridCell *cellLeft = x->getCell(m_columnIndex);
        FCGridCell *cellRight = y->getCell(m_columnIndex);
        if(cellLeft && cellRight){
            if (m_type == 0){
                return cellRight->compareTo(cellLeft) > 0 ? true : false;
            }
            else{
                return cellLeft->compareTo(cellRight) > 0 ? true : false;
            }
        }else{
            return false;
        }
    }
    
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    FCGridSort::FCGridSort(){
    }
    
    FCGridSort::~FCGridSort(){
    }
    
    void FCGridSort::sortColumn(FCGrid *grid, FCGridColumn *column, FCGridColumnSortMode sortMode){
        GridRowCompare compare;
        compare.m_columnIndex = column->getIndex();
        if (sortMode == FCGridColumnSortMode_Asc){
            compare.m_type = 0;
        }
        else{
            compare.m_type = 1;
        }
        std::vector<FCGridRow*> rows;
        for(int i = 0; i < grid->m_rows.size(); i++){
            rows.push_back(grid->m_rows.get(i));
        }
        sort(rows.begin(), rows.end(), compare);
        grid->m_rows.clear();
        std::vector<FCGridRow*>::iterator sIter = rows.begin();
        for(; sIter != rows.end(); ++sIter){
            grid->m_rows.add(*sIter);
        }
        rows.clear();
    }
    
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    

    void FCGrid::callCellEvents(String eventName, FCGridCell *cell){
        if(m_atrEx && m_atrEx->m_events.size() > 0){
            if(m_atrEx->m_events.containsKey(eventName)){
                ArrayList<Object> *events = m_atrEx->m_events.get(eventName);
                ArrayList<Object> *invokes = m_atrEx->m_invokes.get(eventName);
                int eventSize = (int)events->size();
                for(int i = 0; i < eventSize; i++){
                    FCGridCellEventCallBack *func = (FCGridCellEventCallBack*)(events->get(i));
                    func->callGridCellEvent(eventName, this, cell, invokes->get(i));
                }
            }
        }
    }

    void FCGrid::callCellTouchEvents(String eventName, FCGridCell *cell, FCTouchInfo touchInfo){
        if(m_atrEx && m_atrEx->m_events.size() > 0){
            if(m_atrEx->m_events.containsKey(eventName)){
                ArrayList<Object> *events = m_atrEx->m_events.get(eventName);
                ArrayList<Object> *invokes = m_atrEx->m_invokes.get(eventName);
                int eventSize = (int)events->size();
                for(int i = 0; i < eventSize; i++){
                    FCGridCellTouchEventCallBack *func = (FCGridCellTouchEventCallBack*)(events->get(i));
                    func->callGridCellTouchEvent(eventName, this, cell, touchInfo, invokes->get(i));
                }
            }
        }
    }
    
    void FCGrid::touchEvent(FCTouchInfo touchInfo, int state){
        FCPoint mp = touchInfo.m_firstPoint;
        int height = getHeight();
        int hHeight = m_headerVisible ? m_headerHeight : 0;
        int scrollH = 0, scrollV = 0;
        FCHScrollBar *hScrollBar = getHScrollBar();
        FCVScrollBar *vScrollBar = getVScrollBar();
        FCHost *host = getNative()->getHost();
        int vLineSize = 0;
        if (hScrollBar && hScrollBar->isVisible()){
            scrollH = - hScrollBar->getPos();
        }
        if (vScrollBar && vScrollBar->isVisible()){
            scrollV = - vScrollBar->getPos();
            vLineSize = vScrollBar->getLineSize();
        }
        FCPoint fPoint = {0, hHeight + 1};
        FCPoint ePoint = {0, height - 10  + vLineSize};
        FCGridRow *fRow = getRow(fPoint);
        FCGridRow *eRow = getRow(ePoint);
        while (!eRow && ePoint.y > 0){
            ePoint.y -= 10;
            eRow = getRow(ePoint);
        }
        if (fRow && eRow){
            int fIndex = fRow->getIndex();
            int eIndex = eRow->getIndex();
            for (int i = fIndex; i <= eIndex; i++){
                FCGridRow *row = m_rows.get(i);
                if (row->isVisible()){
                    FCRect rowRect = row->getBounds();
                    rowRect.top += scrollV;
                    rowRect.bottom += scrollV;
                    ArrayList<FCGridCell*> cells;
                    ArrayList<FCGridCell*> unFrozenCells;
                    for (int j = 0; j < 2; j++){
                        if (j == 0){
                            cells = row->m_cells;
                        }
                        else{
                            cells = unFrozenCells;
                        }
                        int cellSize = (int)cells.size();
                        for (int c = 0; c < cellSize; c++){
                            FCGridCell *cell = cells.get(c);
                            FCGridColumn *column = cell->getColumn();
                            if (column && column->isVisible()){
                                if (j == 0 && !column->isFrozen()){
                                    unFrozenCells.add(cell);
                                    continue;
                                }
                                FCRect headerRect = column->getHeaderRect();
                                if(!column->isFrozen()){
                                    headerRect.left += scrollH;
                                    headerRect.right += scrollH;
                                }
                                int cellWidth = column->getWidth();
                                int colSpan = cell->getColSpan();
                                if (colSpan > 1){
                                    for (int n = 1; n < colSpan; n++){
                                        FCGridColumn *spanColumn = getColumn(column->getIndex() + n);
                                        if(spanColumn && spanColumn->isVisible()){
                                            cellWidth += spanColumn->getWidth();
                                        }
                                    }
                                }
                                int cellHeight = row->getHeight();
                                int rowSpan = cell->getRowSpan();
                                if (rowSpan > 1){
                                    for (int n = 1; n < rowSpan; n++){
                                        FCGridRow *spanRow = getRow(i + n);
                                        if (spanRow && spanRow->isVisible()){
                                            cellHeight += spanRow->getHeight();
                                        }
                                    }
                                }
                                FCRect cellRect ={headerRect.left, rowRect.top + m_verticalOffset,
                                    headerRect.left + cellWidth, rowRect.top + m_verticalOffset + cellHeight};
                                if (mp.y >= cellRect.top && mp.y <= cellRect.bottom){
                                    if(state == 0){
                                        bool hoverChanged = false;
                                        if (m_allowHoveredRow && m_hoveredRow != row){
                                            m_hoveredRow = row;
                                            hoverChanged = true;
                                        }
                                        if (getNative()->getPushedView() == this){
                                            if (m_allowDragRow && column->allowDragRow()){
                                                m_readyToDragScroll = false;
                                                if (m_selectionMode == FCGridSelectionMode_SelectFullRow){
                                                    int selectedRowsSize = (int)m_selectedRows.size();
                                                    if (selectedRowsSize == 1){
                                                        if (m_selectedRows.get(0) != row){
                                                            moveRow(m_selectedRows.get(0)->getIndex(), row->getIndex());
                                                            onRowDraged();
                                                            hoverChanged = true;
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        if (m_hoveredCell != cell){
                                            if (m_hoveredCell){
                                                onCellTouchLeave(m_hoveredCell, touchInfo);
                                            }
                                            m_hoveredCell = cell;
                                            onCellTouchEnter(m_hoveredCell, touchInfo);
                                        }
                                        onCellTouchMove(cell, touchInfo);
                                        if (!m_editingRow){
                                            if (row->allowEdit()){
                                                if (getNative()->getPushedView() == this){
                                                    int selectedRowsSize = (int)m_selectedRows.size();
                                                    if (selectedRowsSize == 1){
                                                        if (m_selectedRows.get(0) == row){
                                                            onRowEditBegin(row);
                                                            hoverChanged = true;
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        if (hoverChanged){
                                            invalidate();
                                        }
                                    }
                                    else{
                                        if(state == 1){
                                            m_touchDownPoint = mp;
                                            onCellTouchDown(cell, touchInfo);
                                            if(touchInfo.m_firstTouch || touchInfo.m_secondTouch){
                                                int multiSelectMode = 0;
                                                if (m_multiSelect){
                                                    if (host->isKeyPress(VK_SHIFT)){
                                                        multiSelectMode = 1;
                                                    }
                                                    else if (host->isKeyPress(VK_CONTROL)){
                                                        multiSelectMode = 2;
                                                    }
                                                }
                                                if (m_selectionMode == FCGridSelectionMode_SelectCell){
                                                    bool contains = false;
                                                    bool selectedChanged = false;
                                                    int selectedCellSize = (int)m_selectedCells.size();
                                                    if (multiSelectMode == 0 || multiSelectMode == 2){
                                                        for(int c = 0; c < m_selectedCells.size(); c++){
                                                            if(m_selectedCells.get(c) == cell){
                                                                contains = true;
                                                                if (multiSelectMode == 2){
                                                                    m_selectedCells.removeAt(c);
                                                                    selectedChanged = true;
                                                                }
                                                                break;
                                                            }
                                                        }
                                                    }
                                                    if (multiSelectMode == 0){
                                                        selectedCellSize = (int)m_selectedCells.size();
                                                        if (!contains || selectedCellSize > 1){
                                                            m_selectedCells.clear();
                                                            m_selectedCells.add(cell);
                                                            selectedChanged = true;
                                                        }
                                                    }
                                                    else if (multiSelectMode == 2){
                                                        if (!contains){
                                                            m_selectedCells.add(cell);
                                                            selectedChanged = true;
                                                        }
                                                    }
                                                    if (selectedChanged){
                                                        onSelectedCellsChanged();
                                                    }
                                                }
                                                else if (m_selectionMode == FCGridSelectionMode_SelectFullColumn){
                                                    bool contains = false;
                                                    bool selectedChanged = false;
                                                    int selectedColumnsSize = (int)m_selectedColumns.size();
                                                    if (multiSelectMode == 0 || multiSelectMode == 2){
                                                        for(int c = 0; c < m_selectedColumns.size(); c++){
                                                            if(m_selectedColumns.get(c) == column){
                                                                contains = true;
                                                                if (multiSelectMode == 2){
                                                                    m_selectedColumns.removeAt(c);
                                                                    selectedChanged = true;
                                                                }
                                                                break;
                                                            }
                                                        }
                                                    }
                                                    if (multiSelectMode == 0){
                                                        if (!contains || selectedColumnsSize > 1){
                                                            m_selectedColumns.clear();
                                                            m_selectedColumns.add(column);
                                                            selectedChanged = true;
                                                        }
                                                    }
                                                    else if (multiSelectMode == 2){
                                                        if (!contains){
                                                            m_selectedColumns.add(column);
                                                            selectedChanged = true;
                                                        }
                                                    }
                                                    m_selectedCells.clear();
                                                    m_selectedCells.add(cell);
                                                    if (selectedChanged){
                                                        onSelectedColumnsChanged();
                                                    }
                                                }
                                                else if (m_selectionMode == FCGridSelectionMode_SelectFullRow){
                                                    bool contains = false;
                                                    bool selectedChanged = false;
                                                    int selectedRowsSize = (int)m_selectedRows.size();
                                                    if (multiSelectMode == 0 || multiSelectMode == 2){
                                                        for(int s = 0; s < m_selectedRows.size(); s++){
                                                            if(m_selectedRows.get(s) == row){
                                                                contains = true;
                                                                if (multiSelectMode == 2){
                                                                                    m_selectedRows.removeAt(s);
                                                                    selectedChanged = true;
                                                                }
                                                                break;
                                                            }
                                                        }
                                                    }
                                                    if (multiSelectMode == 0){
                                                        selectedRowsSize = (int)m_selectedRows.size();
                                                        if (!contains || selectedRowsSize > 1){
                                                            m_selectedRows.clear();
                                                            m_selectedRows.add(row);
                                                            selectedChanged = true;
                                                        }
                                                    }
                                                    else if (multiSelectMode == 1){
                                                        selectedRowsSize = (int)m_selectedRows.size();
                                                        if (selectedRowsSize > 0){
                                                            int firstIndex = m_selectedRows.get(0)->getIndex();
                                                            int newIndex = row->getIndex();
                                                            int minIndex = FCTran::minValue(firstIndex, newIndex);
                                                            int maxIndex = FCTran::maxValue(firstIndex, newIndex);
                                                            m_selectedRows.clear();
                                                            for (int s = minIndex; s <= maxIndex; s++){
                                                                m_selectedRows.add(getRow(s));
                                                            }
                                                        }
                                                        else{
                                                            m_selectedRows.add(row);
                                                        }
                                                    }
                                                    else if (multiSelectMode == 2){
                                                        if (!contains){
                                                            m_selectedRows.add(row);
                                                            selectedChanged = true;
                                                        }
                                                    }
                                                    m_selectedCells.clear();
                                                    m_selectedCells.add(cell);
                                                    if (selectedChanged){
                                                        onSelectedRowsChanged();
                                                    }
                                                }
                                            }
                                        }
                                        else if(state == 2){
                                            onCellTouchUp(cell, touchInfo);
                                        }
                                        if (state == 2){
                                            if ((int)m_selectedCells.size() > 0 && m_selectedCells.get(0) == cell){
                                                onCellClick(cell, touchInfo);
                                                if (touchInfo.m_firstTouch && cell->allowEdit()){
                                                    if ((m_cellEditMode == FCGridCellEditMode_DoubleClick && touchInfo.m_clicks == 2)
                                                        || (m_cellEditMode == FCGridCellEditMode_SingleClick && touchInfo.m_clicks == 1)){
                                                        onCellEditBegin(cell);
                                                    }
                                                }
                                            }
                                        }
                                        invalidate();
                                    }
                                    unFrozenCells.clear();
                                    if (state == 1 && m_editingRow){
                                        onRowEditEnd();
                                    }
                                    return;
                                }
                            }
                        }
                    }
                    unFrozenCells.clear();
                }
            }
        }
        if (state == 1 && m_editingRow){
            onRowEditEnd();
        }
    }

    
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    int FCGrid::getAllVisibleColumnsWidth(){
        int allVisibleColumnsWidth = 0;
        int colSize = (int)m_columns.size();
        for (int i = 0; i < colSize; i++){
            FCGridColumn *column = m_columns.get(i);
            if (column->isVisible()){
                allVisibleColumnsWidth += column->getWidth();
            }
        }
        return allVisibleColumnsWidth;
    }
    
    int FCGrid::getAllVisibleRowsHeight(){
        int allVisibleRowsHeight = 0;
        int rowSize = (int)m_rows.size();
        for (int i = 0; i < rowSize; i++){
            if (m_rows.get(i)->isVisible()){
                allVisibleRowsHeight += m_rows.get(i)->getHeight();
            }
        }
        return allVisibleRowsHeight;
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    FCGrid::FCGrid(){
        m_allowDragRow = false;
        m_allowHoveredRow = true;
        m_alternateRowStyle = 0;
        m_cellEditMode = FCGridCellEditMode_SingleClick;
        m_editingCell = 0;
        m_editingRow = 0;
        m_editTextBox = 0;
        m_gridLineColor = FCColor::rgb(100, 100, 100);
        m_hasUnVisibleRow = false;
        m_headerVisible = true;
        m_headerHeight = 20;
        m_horizontalOffset = 0;
        m_hoveredCell = 0;
        m_hoveredRow = 0;
        m_lockUpdate = false;
        m_touchDownPoint.x = 0;
        m_touchDownPoint.y = 0;
        m_multiSelect = false;
        m_rowStyle = new FCGridRowStyle;
        m_selectionMode = FCGridSelectionMode_SelectFullRow;
        m_sort = new FCGridSort;
        m_timerID = getNewTimerID();
        m_useAnimation = false;
        m_verticalOffset = 0;
        setShowHScrollBar(true);
        setShowVScrollBar(true);
    }
    
    FCGrid::~FCGrid(){
        stopTimer(m_timerID);
        m_animateAddRows.clear();
        m_animateRemoveRows.clear();
        if(m_alternateRowStyle){
            delete m_alternateRowStyle;
            m_alternateRowStyle = 0;
        }
        if(m_rowStyle){
            delete m_rowStyle;
            m_rowStyle = 0;
        }
        m_editingCell = 0;
        m_editingRow = 0;
        if(m_editTextBox){
            m_editTextBox->removeEvent((FCEventCallBack*)this, L"onlostfocus");
            m_editTextBox->removeEvent((FCKeyEventCallBack*)this, L"onkeydown");
            m_editTextBox = 0;
        }
        m_editTextBox = 0;
        if(m_sort){
            delete m_sort;
            m_sort = 0;
        }
        m_hoveredCell = 0;
        m_hoveredRow = 0;
        clear();
    }
    
    bool FCGrid::allowDragRow(){
        return m_allowDragRow;
    }
    
    void FCGrid::setAllowDragRow(bool value){
        m_allowDragRow = value;
    }
    
    bool FCGrid::allowHoveredRow(){
        return m_allowHoveredRow;
    }
    
    void FCGrid::setAllowHoveredRow(bool value){
        m_allowHoveredRow = value;
    }
    
    FCGridRowStyle* FCGrid::getAlternateRowStyle(){
        return m_alternateRowStyle;
    }
    
    void FCGrid::setAlternateRowStyle(FCGridRowStyle *value){
        if(value){
            if(!m_alternateRowStyle){
                m_alternateRowStyle = new FCGridRowStyle;
            }
            m_alternateRowStyle->copy(value);
        }
        else{
            if(m_alternateRowStyle){
                delete m_alternateRowStyle;
                m_alternateRowStyle = 0;
            }
        }
    }
    
    FCGridCellEditMode FCGrid::getCellEditMode(){
        return m_cellEditMode;
    }
    
    void FCGrid::setCellEditMode(FCGridCellEditMode value){
        m_cellEditMode = value;
    }
    
    FCTextBox* FCGrid::getEditTextBox(){
        return m_editTextBox;
    }
    
    Long FCGrid::getGridLineColor(){
        return m_gridLineColor;
    }
    
    void FCGrid::setGridLineColor(Long value){
        m_gridLineColor = value;
    }
    
    bool FCGrid::isHeaderVisible(){
        return m_headerVisible;
    }
    
    void FCGrid::setHeaderVisible(bool value){
        m_headerVisible = value;
    }
    
    int FCGrid::getHeaderHeight(){
        return m_headerHeight;
    }
    
    void FCGrid::setHeaderHeight(int value){
        m_headerHeight = value;
    }
    
    int FCGrid::getHorizontalOffset(){
        return m_horizontalOffset;
    }
    
    void FCGrid::setHorizontalOffset(int value){
        m_horizontalOffset = value;
    }
    
    FCGridCell* FCGrid::getHoveredCell(){
        return m_hoveredCell;
    }
    
    FCGridRow* FCGrid::getHoveredRow(){
        return m_hoveredRow;
    }
    
    bool FCGrid::isMultiSelect(){
        return m_multiSelect;
    }
    
    void FCGrid::setMultiSelect(bool value){
        m_multiSelect = value;
    }
    
    FCGridRowStyle* FCGrid::getRowStyle(){
        return m_rowStyle;
    }
    
    void FCGrid::setRowStyle(FCGridRowStyle *value){
        if(value){
            if(!m_rowStyle){
                m_rowStyle = new FCGridRowStyle;
            }
            m_rowStyle->copy(value);
        }
        else{
            if(m_rowStyle){
                delete m_rowStyle;
                m_rowStyle = 0;
            }
        }
    }
    
    ArrayList<FCGridCell*> FCGrid::getSelectedCells(){
        return m_selectedCells;
    }
    
    void FCGrid::setSelectedCells(ArrayList<FCGridCell*> value){
        m_selectedCells.clear();
        int selectedCellsSize = (int)value.size();
        for (int i = 0; i < selectedCellsSize; i++){
            m_selectedCells.add(value.get(i));
        }
        onSelectedCellsChanged();
    }
    
    ArrayList<FCGridColumn*> FCGrid::getSelectedColumns(){
        return m_selectedColumns;
    }
    
    void FCGrid::setSelectedColumns(ArrayList<FCGridColumn*> value){
        m_selectedColumns.clear();
        int selectedColumnsSize = (int)value.size();
        for (int i = 0; i < selectedColumnsSize; i++){
            m_selectedColumns.add(value.get(i));
        }
        onSelectedColumnsChanged();
    }
    
    ArrayList<FCGridRow*> FCGrid::getSelectedRows(){
        return m_selectedRows;
    }
    
    void FCGrid::setSelectedRows(ArrayList<FCGridRow*> value){
        m_selectedRows.clear();
        m_selectedCells.clear();
        int selectedRowsSize = (int)value.size();
        for (int i = 0; i < selectedRowsSize; i++){
            m_selectedRows.add(value.get(i));
        }
        onSelectedRowsChanged();
    }
    
    FCGridSelectionMode FCGrid::getSelectionMode(){
        return m_selectionMode;
    }
    
    void FCGrid::setSelectionMode(FCGridSelectionMode value){
        m_selectionMode = value;
    }
    
    FCGridSort* FCGrid::getSort(){
        return m_sort;
    }
    
    void FCGrid::setSort(FCGridSort *value){
        if(m_sort){
            delete m_sort;
        }
        m_sort = value;
    }
    
    bool FCGrid::useAnimation(){
        return m_useAnimation;
    }
    
    void FCGrid::setUseAnimation(bool value){
        m_useAnimation = value;
        if(m_useAnimation){
            startTimer(m_timerID, 20);
        }
        else{
            stopTimer(m_timerID);
        }
    }
    
    int FCGrid::getVerticalOffset(){
        return m_verticalOffset;
    }
    
    void FCGrid::setVerticalOffset(int value){
        m_verticalOffset = value;
    }
    
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    void FCGrid::addColumn(FCGridColumn *column){
        column->setGrid(this);
        m_columns.add(column);
        int columnsSize = (int)m_columns.size();
        for (int i = 0; i < columnsSize; i++){
            m_columns.get(i)->setIndex(i);
        }
        addView(column);
        m_mustUpdate = true;
    }
    
    void FCGrid::addRow(FCGridRow *row){
        if(m_mustUpdate){
            update();
            m_mustUpdate = false;
        }
        row->setGrid(this);
        m_rows.add(row);
        row->onAdd();
        if (m_selectionMode == FCGridSelectionMode_SelectFullRow){
            int selectedRowsSize = (int)m_selectedRows.size();
            if (selectedRowsSize == 0){
                m_selectedRows.add(row);
                onSelectedRowsChanged();
            }
        }
    }
    
    void FCGrid::animateAddRow(FCGridRow *row){
        row->setGrid(this);
        m_rows.add(row);
        row->onAdd();
        if (m_selectionMode == FCGridSelectionMode_SelectFullRow){
            int selectedRowsSize = (int)m_selectedRows.size();
            if (selectedRowsSize == 0){
                m_selectedRows.add(row);
                onSelectedRowsChanged();
            }
        }
        if (m_useAnimation){
            m_animateAddRows.add(row);
        }
    }
    
    void FCGrid::animateRemoveRow(FCGridRow *row){
        if (m_useAnimation){
            m_animateRemoveRows.add(row);
        }
        else{
            removeRow(row);
        }
    }
    
    void FCGrid::beginUpdate(){
        m_lockUpdate = true;
    }

    void FCGrid::callEvent(String eventName, Object sender, Object invoke){
        FCDiv::callEvent(eventName, getTag(), getTag());
        if (eventName == L"onlostfocus" && sender == m_editTextBox) {
            if (m_editTextBox && m_editTextBox->getTag()) {
                Object tempVar = m_editTextBox->getTag();
                onCellEditEnd((FCGridCell*)tempVar);
            }
        }
    }

    void FCGrid::callKeyEvent(String eventName, Object sender, char key, Object invoke){
        FCDiv::callKeyEvent(eventName, sender, key, invoke);
        if (key == 13) {
            if (m_editTextBox && !m_editTextBox->isMultiline()) {
                m_editTextBox->setFocused(false);
            }
        } else if (key == 27) {
            onCellEditEnd(0);
        }
    }
    
    void FCGrid::clear(){
        clearRows();
        clearColumns();
    }
    
    void FCGrid::clearColumns(){
        m_selectedColumns.clear();
        int colSize = (int)m_columns.size();
        for(int i = 0; i < colSize; i++){
            removeView(m_columns.get(i));
            delete m_columns.get(i);
        }
        m_columns.clear();
    }
    
    void FCGrid::clearRows(){
        m_hasUnVisibleRow = false;
        m_hoveredCell = 0;
        m_hoveredRow = 0;
        m_selectedRows.clear();
        m_selectedCells.clear();
        int rowSize = (int)m_rows.size();
        for (int i = 0; i < rowSize; i++){
            m_rows.get(i)->onRemove();
            delete m_rows.get(i);
        }
        m_rows.clear();
    }
    
    void FCGrid::endUpdate(){
        if (m_lockUpdate){
            m_lockUpdate = false;
            update();
        }
    }

    void FCGrid::fastAddColumns(ArrayList<String> texts){
        int textsSize = texts.size();
        for (int i = 0; i < textsSize; i++)
        {
            addColumn(new FCGridColumn(texts.get(i)));
        }
    }
    
    FCGridRow* FCGrid::fastAddRow(ArrayList<String> datas){
        FCGridRow *row = new FCGridRow();
        addRow(row);
        int columnsSize = m_columns.size();
        for (int i = 0; i < columnsSize; i++)
        {
            FCGridColumn *column = m_columns.get(i);
            String cellType = column->getColumnType();
            FCGridCell *cell = 0;
            if (cellType == L"bool"){
                cell = new FCGridBoolCell;
            }
            else if (cellType == L"button"){
                cell = new FCGridButtonCell;
            }
            else if (cellType == L"checkbox"){
                cell = new FCGridCheckBoxCell;
            }
            else if (cellType == L"combobox"){
                cell = new FCGridComboBoxCell;
            }
            else if (cellType == L"double"){
                cell = new FCGridDoubleCell;
            }
            else if (cellType == L"float"){
                cell = new FCGridFloatCell;
            }
            else if (cellType == L"string"){
                cell = new FCGridStringCell;
            }
            else if (cellType == L"int"){
                cell = new FCGridIntCell;
            }
            else if (cellType == L"long"){
                cell = new FCGridLongCell;
            }
            else if (cellType == L"textbox"){
                cell = new FCGridTextBoxCell;
            }
            else if (cellType == L"percent"){
                cell = new FCGridPercentCell;
            }else{
                cell = new FCGridStringCell;
            }
            row->addCell(i, cell);
            cell->setString(datas.get(i));
        }
        return row;
    }
    
    FCGridColumn* FCGrid::getColumn(int columnIndex){
        if (columnIndex >= 0 && columnIndex < (int)m_columns.size()){
            return m_columns.get(columnIndex);
        }
        return 0;
    }
    
    FCGridColumn* FCGrid::getColumn(const String& columnName){
        int colSize = (int)m_columns.size();
        for (int i = 0; i < colSize; i++){
            if (m_columns.get(i)->getName() == columnName){
                return m_columns.get(i);
            }
        }
        return 0;
    }
    
    ArrayList<FCGridColumn*> FCGrid::getColumns(){
        return m_columns;
    }
    
    int FCGrid::getContentHeight(){
        int allVisibleRowsHeight = getAllVisibleRowsHeight();
        if(allVisibleRowsHeight > 0){
            allVisibleRowsHeight += m_headerVisible ? m_headerHeight : 0;
            return allVisibleRowsHeight;
        }
        else{
            return 0;
        }
    }
    
    int FCGrid::getContentWidth(){
        return getAllVisibleColumnsWidth();
    }
    
    String FCGrid::getViewType(){
        return L"Grid";
    }
    
    FCPoint FCGrid::getDisplayOffset(){
        FCPoint offset = {0};
        return offset;
    }
    
    void FCGrid::getAttribute(const String& name, String *value, String *type){
        if(name == L"allowdragrow"){
            *type = L"bool";
            *value = FCTran::boolToStr(allowDragRow());
        }
        else if (name == L"allowhoveredrow"){
            *type = L"bool";
            *value = FCTran::boolToStr(allowHoveredRow());
        }
        else if (name == L"celleditmode"){
            *type = L"enum:FCGridCellEditMode";
            FCGridCellEditMode cellEditMode = getCellEditMode();
            if (cellEditMode == FCGridCellEditMode_DoubleClick){
                *value = L"DoubleClick";
            }
            else if (cellEditMode == FCGridCellEditMode_None){
                *value = L"None";
            }
            else{
                *value = L"SingleClick";
            }
        }
        else if (name == L"columnsize")
       {
           *type = L"int";
           *value = FCTran::intToStr(m_columns.size());
       }
        else if(name == L"gridlinecolor"){
            *type = L"color";
            *value = FCTran::colorToStr(getGridLineColor());
        }
        else if(name == L"headerheight"){
            *type = L"int";
            *value = FCTran::intToStr(getHeaderHeight());
        }
        else if(name == L"headervisible"){
            *type = L"bool";
            *value = FCTran::boolToStr(isHeaderVisible());
        }
        else if(name == L"horizontaloffset"){
            *type = L"int";
            *value = FCTran::intToStr(getHorizontalOffset());
        }
        else if(name == L"multiselect"){
            *type = L"bool";
            *value = FCTran::boolToStr(isMultiSelect());
        }
        else if (name == L"rowsize")
       {
           *type = L"int";
           *value = FCTran::intToStr(m_rows.size());
       }
        else if (name == L"selectionmode"){
            *type = L"enum:FCGridSelectionMode";
            FCGridSelectionMode selectionMode = getSelectionMode();
            if (selectionMode == FCGridSelectionMode_SelectCell){
                *value = L"SelectCell";
            }
            else if (selectionMode == FCGridSelectionMode_SelectFullColumn){
                *value = L"SelectFullColumn";
            }
            else if (selectionMode == FCGridSelectionMode_SelectFullRow){
                *value = L"SelectFullRow";
            }
            else{
                *value = L"none";
            }
        }
        else if(name == L"useanimation"){
            *type = L"bool";
            *value = FCTran::boolToStr(useAnimation());
        }
        else if(name == L"verticaloffset"){
            *type = L"int";
            *value = FCTran::intToStr(getVerticalOffset());
        }
        else{
            FCDiv::getAttribute(name, value, type);
        }
    }

    ArrayList<String> FCGrid::getEventNames(){
        ArrayList<String> eventNames = FCDiv::getEventNames();
        eventNames.add(L"GridCellClick");
        eventNames.add(L"GridCellEditBegin");
        eventNames.add(L"GridCellEditEnd");
        eventNames.add(L"GridCellTouchDown");
        eventNames.add(L"GridCellTouchMove");
        eventNames.add(L"GridCellTouchUp");
        eventNames.add(L"GridSelectedCellsChanged");
        eventNames.add(L"GridSelectedColumnsChanged");
        eventNames.add(L"GridSelectedRowsChanged");
        return eventNames;
    }
    
    ArrayList<String> FCGrid::getAttributeNames(){
        ArrayList<String> attributeNames = FCDiv::getAttributeNames();
        attributeNames.add(L"AllowDragRow");
        attributeNames.add(L"AllowHoveredRow");
        attributeNames.add(L"CellEditMode");
        attributeNames.add(L"GridLineColor");
        attributeNames.add(L"HeaderHeight");
        attributeNames.add(L"HeaderVisible");
        attributeNames.add(L"HorizontalOffset");
        attributeNames.add(L"MultiSelect");
        attributeNames.add(L"SelectionMode");
        attributeNames.add(L"UseAnimation");
        attributeNames.add(L"VerticalOffset");
        return attributeNames;
    }
    
    FCGridRow* FCGrid::getRow(const FCPoint& mp){
        int scrollV = 0;
        FCVScrollBar *vScrollBar = getVScrollBar();
        FCHost *host = getNative()->getHost();
        if (vScrollBar && vScrollBar->isVisible()){
            scrollV = - vScrollBar->getPos();
        }
        FCPoint tPoint = mp;
        tPoint.y -= scrollV;
        if (m_hasUnVisibleRow){
            int rowsSize = (int)m_rows.size();
            for (int i = 0; i < rowsSize; i++){
                FCGridRow *row = m_rows.get(i);
                if (row->isVisible()){
                    FCRect bounds = row->getBounds();
                    if (tPoint.y >= bounds.top && tPoint.y <= bounds.bottom){
                        return row;
                    }
                }
            }
        }
        else{
            int begin = 0;
            int end = (int)m_rows.size() - 1;
            int sub = end - begin;
            while (sub >= 0){
                int half = begin + sub / 2;
                FCGridRow *row = m_rows.get(half);
                FCRect bounds = row->getBounds();
                if (half == begin || half == end){
                    if (tPoint.y >= m_rows.get(begin)->getBounds().top && tPoint.y <= m_rows.get(begin)->getBounds().bottom){
                        return m_rows.get(begin);
                    }
                    if (tPoint.y >= m_rows.get(end)->getBounds().top && tPoint.y <= m_rows.get(end)->getBounds().bottom){
                        return m_rows.get(end);
                    }
                    break;
                }
                if (tPoint.y >= bounds.top && tPoint.y <= bounds.bottom){
                    return row;
                }
                else if (bounds.top > tPoint.y){
                    end = half;
                }
                else if (bounds.bottom < tPoint.y){
                    begin = half;
                }
                sub = end - begin;
            }
        }
        return 0;
    }
    
    FCGridRow* FCGrid::getRow(int rowIndex){
        if (rowIndex >= 0 && rowIndex < (int)m_rows.size()){
            return m_rows.get(rowIndex);
        }
        return 0;
    }
    
    ArrayList<FCGridRow*> FCGrid::getRows(){
        return m_rows;
    }
    
    void FCGrid::getVisibleRowsIndex(double visiblePercent, int *firstVisibleRowIndex, int *lastVisibleRowIndex){
        *firstVisibleRowIndex = -1;
        *lastVisibleRowIndex = -1;
        int rowsSize = (int)m_rows.size();
        if (rowsSize > 0){
            for (int i = 0; i < rowsSize; i++){
                FCGridRow *row = m_rows.get(i);
                if (isRowVisible(row, visiblePercent)){
                    if (*firstVisibleRowIndex == -1){
                        *firstVisibleRowIndex = i;
                    }
                }
                else{
                    if (*firstVisibleRowIndex != -1){
                        *lastVisibleRowIndex = i;
                        break;
                    }
                }
            }
            if (*firstVisibleRowIndex != -1 && *lastVisibleRowIndex == -1){
                *lastVisibleRowIndex = *firstVisibleRowIndex;
            }
        }
    }
    
    void FCGrid::insertRow(int index, FCGridRow *row){
        row->setGrid(this);
        m_rows.insert(index, row);
        row->onAdd();
    }
    
    bool FCGrid::isRowVisible(FCRect *bounds, int rowHeight, int scrollV, double visiblePercent, int cell, int floor){
        int rowtop = bounds->top + scrollV;
        int rowbottom = bounds->bottom + scrollV;
        if (rowtop < cell){
            rowtop = cell;
        }
        else if (rowtop > floor){
            rowtop = floor;
        }
        if (rowbottom < cell){
            rowbottom = cell;
        }
        else if (rowbottom > floor){
            rowbottom = floor;
        }
        if (rowbottom - rowtop >= (int)(rowHeight * visiblePercent)){
            return true;
        }
        return false;
    }
    
    bool FCGrid::isRowVisible(FCGridRow *row, double visiblePercent){
        int scrollV = 0;
        FCVScrollBar *vScrollBar = getVScrollBar();
        if (vScrollBar && vScrollBar->isVisible()){
            scrollV = -vScrollBar->getPos();
        }
        int cell = m_headerVisible ? m_headerHeight : 0;
        int floor = getHeight() - cell;
        FCRect bounds = row->getBounds();
        return isRowVisible(&bounds, row->getHeight(), scrollV, visiblePercent, cell, floor);
    }
    
    void FCGrid::moveRow(int oldIndex, int newIndex){
        int rowsSize = (int)m_rows.size();
        if (rowsSize > 0){
            if (oldIndex >= 0 && oldIndex < rowsSize
                && newIndex >= 0 && newIndex < rowsSize){
                FCGridRow *movingRow = m_rows.get(oldIndex);
                FCGridRow *targetRow = m_rows.get(newIndex);
                if (movingRow != targetRow){
                    m_rows.set(newIndex, movingRow);
                    m_rows.set(oldIndex, targetRow);
                    movingRow->setIndex(newIndex);
                    targetRow->setIndex(oldIndex);
                    FCVScrollBar *vScrollBar = getVScrollBar();
                    if (vScrollBar && vScrollBar->isVisible()){
                        int firstVisibleRowIndex = -1, lastVisibleRowIndex = -1;
                        getVisibleRowsIndex(0.6, &firstVisibleRowIndex, &lastVisibleRowIndex);
                        int th = targetRow->getHeight();
                        if (newIndex <= firstVisibleRowIndex){
                            if (newIndex == firstVisibleRowIndex){
                                vScrollBar->setPos(vScrollBar->getPos() - th);
                            }
                            int count = 0;
                            while (!isRowVisible(targetRow, 0.6)){
                                int newPos = vScrollBar->getPos() - th;
                                vScrollBar->setPos(newPos);
                                count++;
                                if(count > rowsSize || newPos <= vScrollBar->getPos()){
                                    break;
                                }
                            }
                        }
                        else if (newIndex >= lastVisibleRowIndex){
                            if (newIndex == lastVisibleRowIndex){
                                vScrollBar->setPos(vScrollBar->getPos() + th);
                            }
                            int count = 0;
                            while (!isRowVisible(targetRow, 0.6)){
                                int newPos = vScrollBar->getPos() + th;
                                vScrollBar->setPos(newPos);
                                count++;
                                if(count > rowsSize || newPos >= vScrollBar->getPos()){
                                    break;
                                }
                            }
                        }
                        vScrollBar->update();
                    }
                    update();
                }
            }
        }
    }
    
    void FCGrid::onCellClick(FCGridCell *cell, FCTouchInfo touchInfo){
        callCellTouchEvents(L"ongridcellclick", cell, touchInfo);
    }
    
    void FCGrid::onCellEditBegin(FCGridCell *cell){
        m_editingCell = cell;
        if (!m_editTextBox){
            FCHost *host = getNative()->getHost();
            m_editTextBox = dynamic_cast<FCTextBox*>(host->createInternalView(this, L"edittextbox"));
            m_editTextBox->addEvent((FCEventCallBack*)this, L"onlostfocus", this);
            m_editTextBox->addEvent((FCKeyEventCallBack*)this, L"onkeydown", this);
            addView(m_editTextBox);
        }
        m_editTextBox->setFocused(true);
        m_editTextBox->setTag(m_editingCell);
        String text = m_editingCell->getText();
        m_editTextBox->setText(text);
        m_editTextBox->clearRedoUndo();
        m_editTextBox->setVisible(true);
        if((int)text.length() > 0){
            m_editTextBox->setSelectionStart((int)text.length());
        }
        callCellEvents(L"ongridcelleditbegin", cell);
    }
    
    void FCGrid::onCellEditEnd(FCGridCell *cell){
        if(cell){
            cell->setText(m_editTextBox->getText());
        }
        m_editTextBox->setTag(0);
        m_editTextBox->setVisible(false);
        m_editingCell = 0;
        callCellEvents(L"ongridcelleditend", cell);
        invalidate();
    }
    
    void FCGrid::onCellTouchDown(FCGridCell *cell, FCTouchInfo touchInfo){
        callCellTouchEvents(L"ongridcelltouchdown", cell, touchInfo);
    }
    
    void FCGrid::onCellTouchEnter(FCGridCell *cell, FCTouchInfo touchInfo){
        callCellTouchEvents(L"ongridcelltouchenter", cell, touchInfo);
        if (autoEllipsis() || (cell->getStyle() && cell->getStyle()->autoEllipsis())){
            m_native->getHost()->showToolTip(cell->getPaintText(), m_native->getTouchPoint());
        }
    }
    
    void FCGrid::onCellTouchLeave(FCGridCell *cell, FCTouchInfo touchInfo){
        callCellTouchEvents(L"ongridcelltouchleave", cell, touchInfo);
    }
    
    void FCGrid::onCellTouchMove(FCGridCell *cell, FCTouchInfo touchInfo){
        callCellTouchEvents(L"ongridcelltouchmove", cell, touchInfo);
    }
    
    void FCGrid::onCellTouchUp(FCGridCell *cell, FCTouchInfo touchInfo){
        callCellTouchEvents(L"ongridcelltouchup", cell, touchInfo);
    }

    void FCGrid::onCopy(){
        ArrayList<FCGridCell*> selectedCells = getSelectedCells();
        int selectedCellsSize = selectedCells.size();
        if (selectedCellsSize > 0)
        {
            FCHost *host = getNative()->getHost();
            String text = selectedCells.get(0)->getString();
            if((int)text.length() > 0){
                lstring str = FCTran::StringTostring(text);
                host->copy(str);
                FCDiv::onCopy();
            }
        }
    }

    bool FCGrid::onDragScrollPermit(){
        if (m_editingCell || m_editingRow)
        {
            return false;
        }
        return FCDiv::onDragScrollPermit();
    }

    void FCGrid::onRowDraged(){
        callEvents(L"ongridrowdraged");
    }
    
    void FCGrid::onKeyDown(char key){
        FCHost *host = getNative()->getHost();
        if(!host->isKeyPress(VK_CONTROL)
           && !host->isKeyPress(VK_MENU)
           && !host->isKeyPress(VK_SHIFT)){
            if (key == 38 || key == 40){
                callKeyEvents(L"onkeydown", key);
                FCGridRow *row = 0;
                int offset = 0;
                if (key == 38){
                    row = selectFrontRow();
                    if(row){
                        offset = -row->getHeight();
                    }
                }
                else if (key == 40){
                    row = selectNextRow();
                    if(row){
                        offset = row->getHeight();
                    }
                }
                if (row && !isRowVisible(row, 0.6)){
                    FCVScrollBar *vScrollBar = getVScrollBar();
                    if (vScrollBar && vScrollBar->isVisible()){
                        vScrollBar->setPos(vScrollBar->getPos() + offset);
                        vScrollBar->update();
                    }
                }
                invalidate();
                return;
            }
        }
        FCDiv::onKeyDown(key);
    }
    
    void FCGrid::onLoad(){
        FCDiv::onLoad();
        if(m_useAnimation){
            startTimer(m_timerID, 20);
        }
        else{
            stopTimer(m_timerID);
        }
    }
    
    void FCGrid::onLostFocus(){
        FCDiv::onLostFocus();
        m_hoveredCell = 0;
        m_hoveredRow = 0;
    }
    
    void FCGrid::onTouchDown(FCTouchInfo touchInfo){
        FCDiv::onTouchDown(touchInfo);
        touchEvent(touchInfo, 1);
    }
    
    void FCGrid::onTouchLeave(FCTouchInfo touchInfo){
        FCDiv::onTouchLeave(touchInfo);
        if (m_hoveredCell){
            onCellTouchLeave(m_hoveredCell, touchInfo);
            m_hoveredCell = 0;
        }
        m_hoveredRow = 0;
        invalidate();
    }
    
    void FCGrid::onTouchMove(FCTouchInfo touchInfo){
        FCDiv::onTouchMove(touchInfo);
        touchEvent(touchInfo, 0);
    }
    
    void FCGrid::onTouchUp(FCTouchInfo touchInfo){
        FCDiv::onTouchUp(touchInfo);
        touchEvent(touchInfo, 2);
    }
    
    void FCGrid::onPaintForeground(FCPaint *paint, const FCRect& clipRect){
        resetHeaderLayout();
        int width = getWidth(), height = getHeight();
        if (width > 0 && height > 0){
            FCHost *host = getNative()->getHost();
            FCRect rect = {0, 0, width, height};
            int allVisibleColumnsWidth = getAllVisibleColumnsWidth();
            int rowVisibleWidth = 0;
            if (allVisibleColumnsWidth > 0){
                rowVisibleWidth = allVisibleColumnsWidth > width ? width : allVisibleColumnsWidth;
            }
            int hHeight = m_headerVisible ? m_headerHeight : 0;
            int scrollH = 0, scrollV = 0;
            FCHScrollBar *hScrollBar = getHScrollBar();
            FCVScrollBar *vScrollBar = getVScrollBar();
            if (hScrollBar && hScrollBar->isVisible()){
                scrollH = - hScrollBar->getPos();
            }
            if (vScrollBar && vScrollBar->isVisible()){
                scrollV = - vScrollBar->getPos();
            }
            onSetEmptyClipRegion();
            FCPoint fPoint ={0, hHeight + 1};
            FCPoint ePoint ={0, height - 10};
            FCGridRow *fRow = getRow(fPoint);
            FCGridRow *eRow = getRow(ePoint);
            while (!eRow && ePoint.y > 0){
                ePoint.y -= 10;
                eRow = getRow(ePoint);
            }
            if (fRow && eRow){
                int fIndex = fRow->getIndex();
                int eIndex = eRow->getIndex();
                for (int i = fIndex; i <= eIndex; i++){
                    FCGridRow *row = m_rows.get(i);
                    if (row->isVisible()){
                        FCRect rowRect = row->getBounds();
                        rowRect.top += scrollV;
                        rowRect.bottom += scrollV;
                        row->onPaint(paint, rowRect, row->getVisibleIndex() % 2 == 1);
                        FCRect tempRect ={0};
                        ArrayList<FCGridCell*> cells;
                        ArrayList<FCGridCell*> frozenCells;
                        for (int j = 0; j < 2; j++){
                            if (j == 0){
                                cells = row->m_cells;
                            }
                            else{
                                cells = frozenCells;
                            }
                            int frozenRight = 0;
                            int cellSize = (int)cells.size();
                            for (int c = 0; c < cellSize; c++){
                                FCGridCell *cell = cells.get(c);
                                FCGridColumn *column = cell->getColumn();
                                if (column && column->isVisible()){
                                    FCRect headerRect = column->getHeaderRect();
                                    if (j == 0 && column->isFrozen()){
                                        frozenRight = headerRect.right;
                                        frozenCells.add(cell);
                                        continue;
                                    }
                                    if(!column->isFrozen()){
                                        headerRect.left += scrollH;
                                        headerRect.right += scrollH;
                                    }
                                    int cellWidth = column->getWidth();
                                    int colSpan = cell->getColSpan();
                                    if (colSpan > 1){
                                        for (int n = 1; n < colSpan; n++){
                                            FCGridColumn *spanColumn = getColumn(column->getIndex() + n);
                                            if(spanColumn && spanColumn->isVisible()){
                                                cellWidth += spanColumn->getWidth();
                                            }
                                        }
                                    }
                                    int cellHeight = row->getHeight();
                                    int rowSpan = cell->getRowSpan();
                                    if (rowSpan > 1){
                                        for (int n = 1; n < rowSpan; n++){
                                            FCGridRow *spanRow = getRow(i + n);
                                            if (spanRow && spanRow->isVisible()){
                                                cellHeight += spanRow->getHeight();
                                            }
                                        }
                                    }
                                    FCRect cellRect ={headerRect.left, rowRect.top + m_verticalOffset, headerRect.left + cellWidth, rowRect.top + m_verticalOffset + cellHeight};
                                    cellRect.left += row->getHorizontalOffset();
                                    cellRect.right += row->getHorizontalOffset();
                                    if (host->getIntersectRect(&tempRect, &rect, &cellRect)){
                                        if (cell){
                                            FCRect cellClipRect = cellRect;
                                            if(!column->isFrozen()){
                                                if (cellClipRect.left < frozenRight){
                                                    cellClipRect.left = frozenRight;
                                                }
                                                if (cellClipRect.right < frozenRight){
                                                    cellClipRect.right = frozenRight;
                                                }
                                            }
                                            //cellRect.left -= 1;
                                            cell->onPaint(paint, cellRect, cellClipRect, row->getVisibleIndex() % 2 == 1);
                                            if (m_editingCell && m_editingCell == cell && m_editTextBox){
                                                FCRect editClipRect ={cellClipRect.left - cellRect.left, cellClipRect.top - cellRect.top,
                                                    cellClipRect.right - cellRect.left, cellClipRect.bottom - cellRect.top};
                                                onPaintEditTextBox(cell, paint, cellRect, editClipRect);
                                            }
                                            if(m_gridLineColor != FCColor_None){
                                                if (i == fIndex){
                                                    paint->drawLine(m_gridLineColor, 1, 0, cellClipRect.left, cellClipRect.top, cellClipRect.right - 1, cellClipRect.top);
                                                }
                                                if (c == 0){
                                                    paint->drawLine(m_gridLineColor, 1, 0, cellClipRect.left, cellClipRect.top, cellClipRect.left, cellClipRect.bottom - 1);
                                                }
                                                paint->drawLine(m_gridLineColor, 1, 0, cellClipRect.left, cellClipRect.bottom - 1, cellClipRect.right - 1, cellClipRect.bottom - 1);
                                                paint->drawLine(m_gridLineColor, 1, 0, cellClipRect.right - 1, cellClipRect.top, cellClipRect.right - 1, cellClipRect.bottom - 1);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        frozenCells.clear();
                        row->onPaintBorder(paint, rowRect, row->getVisibleIndex() % 2 == 1);
                    }
                }
            }
        }
    }
    
    void FCGrid::onPaintEditTextBox(FCGridCell *cell, FCPaint *paint, const FCRect& rect, const FCRect& clipRect){
        m_editTextBox->setRegion(clipRect);
        m_editTextBox->setBounds(rect);
        m_editTextBox->setDisplayOffset(false);
        m_editTextBox->bringToFront();
    }
    
    void FCGrid::onRowEditBegin(FCGridRow *row){
        FCView *editButton = row->getEditButton();
        if (editButton && !containsView(editButton)){
            FCPoint mp = getTouchPoint();
            if (mp.x - m_touchDownPoint.x < -10 && abs(mp.y - m_touchDownPoint.y) < 30){
                m_editingRow = row;
                addView(editButton);
                if (m_useAnimation){
                    FCPoint location ={-10000, -10000};
                    editButton->setLocation(location);
                    m_editingRow->m_editState = 1;
                }
                else{
                    m_editingRow->setHorizontalOffset(-editButton->getWidth() - ((m_vScrollBar && m_vScrollBar->isVisible()) ? m_vScrollBar->getWidth() : 0));
                }
            }
        }
    }
    
    void FCGrid::onRowEditEnd(){
        if(m_editingRow){
            if (m_useAnimation){
                    m_editingRow->m_editState = 2;
            }
            else{
                    m_editingRow->setHorizontalOffset(0);
                    removeView(m_editingRow->getEditButton());
                    m_editingRow = 0;
            }
        }
    }

    void FCGrid::onScaling(double scaleFactorX, double scaleFactorY) {
        m_headerHeight = (int)(m_headerHeight * scaleFactorY);
        FCView::onScaling(scaleFactorX, scaleFactorY);
        if (m_rowStyle) {
            m_rowStyle->m_font->m_fontSize = (float)(m_rowStyle->m_font->m_fontSize * (scaleFactorX + scaleFactorY) / 2);
        }
        if (m_alternateRowStyle) {
            m_alternateRowStyle->m_font->m_fontSize = (float)(m_alternateRowStyle->m_font->m_fontSize * (scaleFactorX + scaleFactorY) / 2);
        }
        int rowsSize = m_rows.size();
        for (int i = 0; i < rowsSize; i++) {
            m_rows.get(i)->onScaling(scaleFactorX, scaleFactorY);
        }
    }
    
    void FCGrid::onSelectedCellsChanged(){
        callEvents(L"ongridselectedcellschanged");
    }
    
    void FCGrid::onSelectedColumnsChanged(){
        callEvents(L"ongridselectedcolumnschanged");
    }
    
    void FCGrid::onSelectedRowsChanged(){
        callEvents(L"ongridselectedrowschanged");
    }
    
    void FCGrid::onSetEmptyClipRegion(){
        ArrayList<FCView*> views = getViews();
        FCRect emptyClipRect = {0};
        for(int c = 0; c < views.size(); c++){
            FCView *view = views.get(c);
            if (m_editingRow && view == m_editingRow->getEditButton()){
                continue;
            }
            FCScrollBar *scrollBar = dynamic_cast<FCScrollBar*>(view);
            FCGridColumn *gridColumn = dynamic_cast<FCGridColumn*>(view);
            if (view != m_editTextBox && !scrollBar && !gridColumn){
                view->setRegion(emptyClipRect);
            }
        }
    }
    
    void FCGrid::onTimer(int timerID){
        FCDiv::onTimer(timerID);
        if (m_timerID == timerID){
            if(m_useAnimation){
                bool paint = false;
                if (m_horizontalOffset != 0 || m_verticalOffset != 0){
                    if (m_horizontalOffset != 0){
                        m_horizontalOffset = m_horizontalOffset * 2 / 3;
                        if (m_horizontalOffset >= -1 && m_horizontalOffset <= 1){
                            m_horizontalOffset = 0;
                        }
                    }
                    if (m_verticalOffset != 0){
                        m_verticalOffset = m_verticalOffset * 2 / 3;
                        if (m_verticalOffset >= -1 && m_verticalOffset <= 1){
                            m_verticalOffset = 0;
                        }
                    }
                    paint = true;
                }
                int animateAddRowsSize = (int)m_animateAddRows.size();
                if (animateAddRowsSize > 0){
                    int width = getAllVisibleColumnsWidth();
                    int step = width / 10;
                    if (step < 10){
                        step = 10;
                    }
                    for (int i = 0; i < animateAddRowsSize; i++){
                        FCGridRow *row = m_animateAddRows.get(i);
                        int horizontalOffset = row->getHorizontalOffset();
                        if (horizontalOffset > step){
                            horizontalOffset -= step;
                        }
                        else{
                            horizontalOffset = 0;
                        }
                        row->setHorizontalOffset(horizontalOffset);
                        if (horizontalOffset == 0){
                            m_animateAddRows.removeAt(i);
                            animateAddRowsSize--;
                            i--;
                        }
                    }
                    paint = true;
                }
                int animateRemoveRowsSize = (int)m_animateRemoveRows.size();
                if (animateRemoveRowsSize > 0){
                    int width = getAllVisibleColumnsWidth();
                    int step = width / 10;
                    if (step < 10){
                        step = 10;
                    }
                    for (int i = 0; i < animateRemoveRowsSize; i++){
                        FCGridRow *row = m_animateRemoveRows.get(i);
                        int horizontalOffset = row->getHorizontalOffset();
                        if (horizontalOffset <= width){
                            horizontalOffset += step;
                        }
                        row->setHorizontalOffset(horizontalOffset);
                        if (horizontalOffset > width){
                            m_animateRemoveRows.removeAt(i);
                            removeRow(row);
                            update();
                            animateRemoveRowsSize--;
                            i--;
                        }
                    }
                    paint = true;
                }
                if (m_editingRow){
                    int scrollH = 0, scrollV = 0;
                    FCHScrollBar *hScrollBar = getHScrollBar();
                    FCVScrollBar *vScrollBar = getVScrollBar();
                    int vScrollBarW = 0;
                    if (hScrollBar && hScrollBar->isVisible()){
                        scrollH = -hScrollBar->getPos();
                    }
                    if (vScrollBar && vScrollBar->isVisible()){
                        scrollV = -vScrollBar->getPos();
                        vScrollBarW = vScrollBar->getWidth();
                    }
                    if (m_editingRow->m_editState == 1){
                        FCView *editButton = m_editingRow->getEditButton();
                        bool isOver = false;
                        int sub = editButton->getWidth() + vScrollBarW + m_editingRow->getHorizontalOffset();
                        if (sub < 2){
                            isOver = true;
                            m_editingRow->setHorizontalOffset(-editButton->getWidth() - vScrollBarW);
                        }
                        else{
                            m_editingRow->setHorizontalOffset(m_editingRow->getHorizontalOffset() - 10);
                        }
                        FCPoint newLocation ={getAllVisibleColumnsWidth() + scrollH + m_editingRow->getHorizontalOffset(),
                            m_editingRow->getBounds().top + scrollV};
                        editButton->setLocation(newLocation);
                        if (isOver){
                            m_editingRow->m_editState = 0;
                        }
                    }
                    if (m_editingRow->m_editState == 2){
                        FCView *editButton = m_editingRow->getEditButton();
                        bool isOver = false;
                        if (m_editingRow->getHorizontalOffset() < 0){
                            m_editingRow->setHorizontalOffset(m_editingRow->getHorizontalOffset() + 10);
                            if (m_editingRow->getHorizontalOffset() >= 0){
                                m_editingRow->setHorizontalOffset(0);
                                isOver = true;
                            }
                        }
                        FCPoint newLocation ={getAllVisibleColumnsWidth() + scrollH + m_editingRow->getHorizontalOffset(),
                            m_editingRow->getBounds().top + scrollV};
                        editButton->setLocation(newLocation);
                        if (isOver){
                            removeView(editButton);
                            m_editingRow->m_editState = 0;
                            m_editingRow = 0;
                        }
                    }
                    paint = true;
                }
                if (paint){
                    invalidate();
                }
            }
        }
    }
    
    
    void FCGrid::onVisibleChanged(){
        FCDiv::onVisibleChanged();
        m_hoveredCell = 0;
        m_hoveredRow = 0;
    }
    
    void FCGrid::removeColumn(FCGridColumn *column){
        bool selectedChanged = false;
        for(int i = 0; i < m_selectedColumns.size(); i++){
            if(m_selectedColumns.get(i) != column){
                m_selectedColumns.removeAt(i);
                selectedChanged = true;
                break;
            }
        }
        for(int i = 0; i < m_columns.size(); i++){
            if(m_columns.get(i) == column){
                m_columns.removeAt(i);
                int columnsSize = (int)m_columns.size();
                for (int i = 0; i < columnsSize; i++){
                    m_columns.get(i)->setIndex(i);
                }
                removeView(column);
                break;
            }
        }
        int rowSize = (int)m_rows.size();
        for (int i = 0; i < rowSize; i++){
            FCGridRow *row = m_rows.get(i);
            row->removeCell(column->getIndex());
        }
        if(selectedChanged){
            onSelectedColumnsChanged();
        }
    }
    
    void FCGrid::removeRow(FCGridRow *row){
        if (m_editingRow){
            if (containsView(m_editingRow->getEditButton())){
                removeView(m_editingRow->getEditButton());
            }
            m_editingRow->m_editState = 0;
            m_editingRow = 0;
        }
        int animateAddRowsSize = m_animateAddRows.size();
        for(int i = 0; i < animateAddRowsSize; i++){
            if(m_animateAddRows.get(i) ==  row){
                m_animateAddRows.removeAt(i);
                break;
            }
        }
        bool selectedChanged = false;
        bool selected = false;
        int selectedRowsSize = (int)m_selectedRows.size();
        for (int i = 0; i < selectedRowsSize; i++){
            FCGridRow *selectedRow = m_selectedRows.get(i);
            if (selectedRow == row){
                selected = true;
                break;
            }
        }
        if (selected){
            if(row->getIndex() == 0){
                FCGridRow *otherRow = selectNextRow();
                if (otherRow){
                    selectedChanged = true;
                }
                else{
                    otherRow = selectFrontRow();
                    if(otherRow){
                        selectedChanged = true;
                    }
                }
            }else{
                FCGridRow *otherRow = selectFrontRow();
                if (otherRow){
                    selectedChanged = true;
                }
                else{
                    otherRow = selectNextRow();
                    if(otherRow){
                        selectedChanged = true;
                    }
                }
            }
        }
        if (m_hoveredRow == row){
            m_hoveredCell = 0;
            m_hoveredRow = 0;
        }
        for(int i = 0; i < m_rows.size(); i++){
            if(m_rows.get(i) == row){
                row->onRemove();
                m_rows.removeAt(i);
                break;
            }
        }
        int rowSize = (int)m_rows.size();
        if(rowSize == 0){
            m_selectedCells.clear();
            m_selectedRows.clear();
        }
        int visibleIndex = 0;
        for (int i = 0; i < rowSize; i++){
            FCGridRow *FCGridRow = m_rows.get(i);
            FCGridRow->setIndex(i);
            if(FCGridRow->isVisible()){
                FCGridRow->setVisibleIndex(visibleIndex);
                visibleIndex++;
            }
        }
        if(selected){
            if(selectedChanged){
                onSelectedRowsChanged();
            }
            else{
                m_selectedCells.clear();
                m_selectedRows.clear();
            }
        }
    }
    
    void FCGrid::resetHeaderLayout(){
        if (!m_lockUpdate){
            int left = 0, top =0;
            int scrollH = 0, scrollV = 0;
            FCHScrollBar *hScrollBar = getHScrollBar();
            FCVScrollBar *vScrollBar = getVScrollBar();
            int vScrollBarW = 0;
            if (hScrollBar && hScrollBar->isVisible()){
                scrollH = -hScrollBar->getPos();
            }
            if (vScrollBar && vScrollBar->isVisible()){
                scrollV = -vScrollBar->getPos();
                vScrollBarW = vScrollBar->getWidth();
            }
            int headerHeight = m_headerVisible ? m_headerHeight : 0;
            FCGridColumn *draggingColumn = 0;
            int colSize = (int)m_columns.size();
            for (int i = 0; i < colSize; i++){
                FCGridColumn *column = m_columns.get(i);
                if (column->isVisible()){
                    FCRect cellRect ={left + m_horizontalOffset, top + m_verticalOffset,
                        left + m_horizontalOffset + column->getWidth(), top + headerHeight + m_verticalOffset};
                    column->setHeaderRect(cellRect);
                    if (column->isDragging()){
                        draggingColumn = column;
                        FCRect newRect ={column->getLeft(), cellRect.top, column->getRight(), cellRect.bottom};
                        column->setBounds(newRect);
                    }
                    else{
                        if (!column->isFrozen()){
                            cellRect.left += scrollH;
                            cellRect.right += scrollH;
                        }
                        column->setBounds(cellRect);
                    }
                    left += column->getWidth();
                }
            }
            for (int i = colSize - 1; i >= 0; i--){
                m_columns.get(i)->bringToFront();
            }
            if(draggingColumn){
                draggingColumn->bringToFront();
            }
            if (m_editingRow && m_editingRow->m_editState == 0 && m_editingRow->getEditButton()){
                FCView *editButton = m_editingRow->getEditButton();
                FCPoint newLocation ={getAllVisibleColumnsWidth() - editButton->getWidth() + scrollH - vScrollBarW, m_editingRow->getBounds().top + scrollV};
                editButton->setLocation(newLocation);
            }
        }
    }
    
    FCGridRow* FCGrid::selectFrontRow(){
        int rowsSize = (int)m_rows.size();
        if (rowsSize == 0){
            m_selectedCells.clear();
            m_selectedRows.clear();
            return 0;
        }
        FCGridRow *frontRow = 0;
        ArrayList<FCGridRow*> selectedRows = getSelectedRows();
        if ((int)selectedRows.size() == 1){
            FCGridRow *selectedRow = selectedRows.get(0);
            int selectedIndex = selectedRow->getIndex();
            for (int i = selectedIndex - 1; i >= 0; i--){
                if (i < rowsSize && m_rows.get(i)->isVisible()){
                    frontRow = m_rows.get(i);
                    break;
                }
            }
            if(m_selectionMode == FCGridSelectionMode_SelectFullRow){
                if (frontRow){
                    m_selectedRows.clear();
                    m_selectedCells.clear();
                    m_selectedRows.add(frontRow);
                    onSelectedRowsChanged();
                }
                else{
                    m_selectedRows.clear();
                    m_selectedCells.clear();
                    frontRow = m_rows.get((int)m_rows.size() - 1);
                    m_selectedRows.add(frontRow);
                    FCVScrollBar *vScrollBar = getVScrollBar();
                    if (vScrollBar && vScrollBar->isVisible()){
                        vScrollBar->scrollToEnd();
                    }
                    onSelectedRowsChanged();
                }
            }
        }
        return frontRow;
    }

    FCGridRow* FCGrid::selectFirstRow() {
        int rowsSize = m_rows.size();
        if (rowsSize == 0) {
            m_selectedRows.clear();
            m_selectedCells.clear();
            return 0;
        }
        for (int i = 0; i < rowsSize; i++)
        {
            FCGridRow *firstRow = m_rows.get(i);
            if (firstRow->isVisible())
            {
                m_selectedRows.clear();
                m_selectedCells.clear();
                m_selectedRows.add(firstRow);
                FCVScrollBar *vScrollBar = getVScrollBar();
                if (vScrollBar && vScrollBar->isVisible()) {
                    vScrollBar->scrollToBegin();
                }
                onSelectedRowsChanged();
                return firstRow;
            }
        }
        return 0;
    }

    FCGridRow* FCGrid::selectLastRow() {
        int rowsSize = m_rows.size();
        if (rowsSize == 0) {
            m_selectedRows.clear();
            m_selectedCells.clear();
            return 0;
        }
        for (int i = rowsSize - 1; i >= 0; i--)
        {
            FCGridRow *lastRow = m_rows.get(i);
            if (lastRow->isVisible())
            {
                m_selectedRows.clear();
                m_selectedCells.clear();
                m_selectedRows.add(lastRow);
                FCVScrollBar *vScrollBar = getVScrollBar();
                if (vScrollBar && vScrollBar->isVisible()) {
                    vScrollBar->scrollToEnd();
                }
                onSelectedRowsChanged();
                return lastRow;
            }
        }
        return 0;
    }
    
    FCGridRow* FCGrid::selectNextRow(){
        int rowsSize = (int)m_rows.size();
        if (rowsSize == 0){
            m_selectedCells.clear();
            m_selectedRows.clear();
            return 0;
        }
        FCGridRow *nextRow = 0;
        ArrayList<FCGridRow*> selectedRows = getSelectedRows();
        if ((int)selectedRows.size() == 1){
            FCGridRow *selectedRow = selectedRows.get(0);
            int selectedIndex = selectedRow->getIndex();
            for (int i = selectedIndex + 1; i < rowsSize; i++){
                if (i >= 0 && m_rows.get(i)->isVisible()){
                    nextRow = m_rows.get(i);
                    break;
                }
            }
            if(m_selectionMode == FCGridSelectionMode_SelectFullRow){
                if (nextRow){
                    m_selectedRows.clear();
                    m_selectedCells.clear();
                    m_selectedRows.add(nextRow);
                    onSelectedRowsChanged();
                }
                else{
                    m_selectedRows.clear();
                    m_selectedCells.clear();
                    nextRow = m_rows.get(0);
                    m_selectedRows.add(nextRow);
                    FCVScrollBar *vScrollBar = getVScrollBar();
                    if (vScrollBar && vScrollBar->isVisible()){
                        vScrollBar->scrollToBegin();
                    }
                    onSelectedRowsChanged();
                }
            }
        }
        return nextRow;
    }
    
    void FCGrid::setAttribute(const String& name, const String& value){
        if(name == L"allowdragrow"){
            setAllowDragRow(FCTran::strToBool(value));
        }
        else if (name == L"allowhoveredrow"){
            setAllowHoveredRow(FCTran::strToBool(value));
        }
        else if (name == L"celleditmode"){
            String lowerStr = FCTran::toLower(value);
            if (lowerStr == L"doubleclick"){
                setCellEditMode(FCGridCellEditMode_DoubleClick);
            }
            else if (lowerStr == L"none"){
                setCellEditMode(FCGridCellEditMode_None);
            }
            else if (lowerStr == L"singleclick"){
                setCellEditMode(FCGridCellEditMode_SingleClick);
            }
        }
        else if(name == L"gridlinecolor"){
            setGridLineColor(FCTran::strToColor(value));
        }
        else if(name == L"headerheight"){
            setHeaderHeight(FCTran::strToInt(value));
        }
        else if(name == L"headervisible"){
            setHeaderVisible(FCTran::strToBool(value));
        }
        else if(name == L"horizontaloffset"){
            setHorizontalOffset(FCTran::strToInt(value));
        }
        else if(name == L"multiselect"){
            setMultiSelect(FCTran::strToBool(value));
        }
        else if (name == L"selectionmode"){
            String lowerStr = FCTran::toLower(value);
            if (lowerStr == L"selectcell"){
                setSelectionMode(FCGridSelectionMode_SelectCell);
            }
            else if (lowerStr == L"selectfullcolumn"){
                setSelectionMode(FCGridSelectionMode_SelectFullColumn);
            }
            else if (lowerStr == L"selectfullrow"){
                setSelectionMode(FCGridSelectionMode_SelectFullRow);
            }
            else{
                setSelectionMode(FCGridSelectionMode_SelectNone);
            }
        }
        else if(name == L"useanimation"){
            setUseAnimation(FCTran::strToBool(value));
        }
        else if(name == L"verticaloffset"){
            setVerticalOffset(FCTran::strToInt(value));
        }
        else{
            FCDiv::setAttribute(name, value);
        }
    }
    
    void FCGrid::sortColumn(FCGrid *grid, FCGridColumn *column, FCGridColumnSortMode sortMode){
        if(column->allowSort()){
            int colSize = (int)grid->m_columns.size();
            for (int i = 0; i < colSize; i++){
                if (grid->m_columns.get(i) != column){
                    grid->m_columns.get(i)->setSortMode(FCGridColumnSortMode_None);
                }
                else{
                    grid->m_columns.get(i)->setSortMode(sortMode);
                }
            }
            if(m_sort){
                m_sort->sortColumn(grid, column, sortMode);
            }
            grid->update();
            grid->invalidate();
        }
    }
    
    void FCGrid::update(){
        if(m_native && !m_native->m_lockUpdate){
            if (!m_lockUpdate){
                FCDiv::update();
                if(isVisible()){
                    int colSize = (int)m_columns.size();
                    for (int i = 0; i < colSize; i++){
                        m_columns.get(i)->setIndex(i);
                    }
                    int rowSize = (int)m_rows.size();
                    int visibleIndex = 0;
                    int rowTop = m_headerVisible ? m_headerHeight : 0;
                    int allVisibleColumnsWidth = getAllVisibleColumnsWidth();
                    m_hasUnVisibleRow = false;
                    for (int i = 0; i < rowSize; i++){
                        FCGridRow *FCGridRow = m_rows.get(i);
                        FCGridRow->setIndex(i);
                        if (FCGridRow->isVisible()){
                            FCGridRow->setVisibleIndex(i);
                            int rowHeight = FCGridRow->getHeight();
                            FCRect rowRect ={0, rowTop, allVisibleColumnsWidth, rowTop + rowHeight};
                            FCGridRow->setBounds(rowRect);
                            rowTop += rowHeight;
                            visibleIndex++;
                        }
                        else{
                            m_hasUnVisibleRow = true;
                            FCGridRow->setVisibleIndex(-1);
                            FCRect rowRect ={0, rowTop, allVisibleColumnsWidth, rowTop};
                            FCGridRow->setBounds(rowRect);
                        }
                    }
                    FCHScrollBar *hScrollBar = getHScrollBar();
                    FCVScrollBar *vScrollBar = getVScrollBar();
                    if (vScrollBar && vScrollBar->isVisible()){
                        int top = m_headerVisible ? m_headerHeight : 0;
                        vScrollBar->setTop(top);
                        int height = getHeight() - top - ((hScrollBar && hScrollBar->isVisible()) ? hScrollBar->getHeight() : 0);
                        vScrollBar->setHeight(height);
                        vScrollBar->setPageSize(height);
                        if (rowSize > 0){
                            //vScrollBar->setLineSize(getAllVisibleRowsHeight() / rowSize);
                        }
                    }
                    m_mustUpdate = false;
                }
            }
        }
    }
    
    void FCGrid::updateSortColumn(){
        int colSize = (int)m_columns.size();
        for (int i = 0; i < colSize; i++){
            if (m_columns.get(i)->getSortMode() != FCGridColumnSortMode_None){
                sortColumn(this, m_columns.get(i), m_columns.get(i)->getSortMode());
                break;
            }
        }
    }
}
